<?php

/**
 * 模板引擎类
 */

namespace variant\core;

class Template {

	/**
	 * 模板配置
	 * @var array
	 */
	protected $config =array();

	/**
	 * 标签
	 * @var null
	 */
	protected $label = null;

	/**
	 * 模板赋值数组
	 * @var array
	 */
	protected $vars = array();

	/**
	 * 缓存对象
	 * @var null
	 */
	protected $cache = null;

	/**
	 * 标签定界符
	 */
	protected $__ldel = '{';
    protected $__rdel = '}';
    protected $__ltag = '<!--';
    protected $__rtag = '-->';
    private $_template_preg = array(), $_template_replace = array();


	/**
	 * 构建函数
	 * @param array $config 模板引擎配置
	 */
	public function __construct($config) {
		$this->config = $config;
		$this->assign('__Template', $this);
		$this->cache = new Cache( $this->config['TPL_CACHE'] );
	}
	
	/**
	 * 模板赋值
	 * @param  string $name  变量名
	 * @param  mixed  $value 变量值
	 * @return void
	 */
	public function assign($name, $value = '') {
		if( is_array($name) ){
			foreach($name as $k => $v){
				$this->vars[$k] = $v;
			}
		} else {
			$this->vars[$name] = $value;
		}
	}

	/**
	 * 模板输出
	 * @param  string  $tpl    模板名
	 * @param  boolean $return 返回模板内容
	 * @param  boolean $isTpl  是否模板文件
	 * @return mixed
	 */
	public function display($tpl = '', $return = false, $isTpl = true) {
		if( $return ){
			if ( ob_get_level() ){
				ob_end_flush();
				flush(); 
			} 
			ob_start();
		}
		
		extract($this->vars, EXTR_OVERWRITE);
		eval('?>' . $this->compile( $tpl, $isTpl));
		
		if( $return ){
			$content = ob_get_contents();
			ob_end_clean();
			return $content;
		}
	}

	/**
	 * 模板编译
	 * @param  string  $tpl    模板名
	 * @param  boolean $isTpl  是否模板文件
	 * @return string
	 */	
	public function compile($tpl, $isTpl = true) {
		if( $isTpl ){
			$tplFile = BASE_PATH . $tpl . $this->config['TPL_SUFFIX'];
			if ( !file_exists($tplFile) ) {
				throw new \Exception("Template file '{$tplFile}' not found", 500);
			}
			$tplKey = md5(realpath($tplFile));				
		} else {
			$tplKey = md5($tpl);
		}

		$ret = unserialize( $this->cache->get( $tplKey ) );	
		if ( empty($ret['template']) || ($isTpl&&filemtime($tplFile)>($ret['compile_time'])) ) {
			$template = $isTpl ? file_get_contents( $tplFile ) : $tpl;
			$template = $this->templateParse($template);
			$ret = array('template'=>$template, 'compile_time'=>time());
			$this->cache->set( $tplKey, serialize($ret), 86400*365);
		}	
		return $ret['template'];
	}

	/**
	 * 模板解析
	 * @param  string $template 模板内容
	 * @return string
	 */
	public function templateParse($template){
       
        //替换判断
        $this->_template_preg[] = '/' . $this->__ltag . "if\{(.*?)\}" . $this->__rtag . '/i';
        $this->_template_preg[] = '/' . $this->__ltag . '\{else\}' . $this->__rtag . '/i';
        $this->_template_preg[] = '/' . $this->__ltag . '(else if|elseif)\{(.*?)\}' . $this->__rtag . '/i';

        $this->_template_replace[] = '<?php if (\\1){ ?>';
        $this->_template_replace[] = '<?php }else{ ?>';
        $this->_template_replace[] = '<?php }else if (\\2){ ?>';

        //替换循环
        $this->_template_preg[] = '/' . $this->__ltag . '(loop|foreach)\{(.*?)\}' . $this->__rtag . '/i';
        $this->_template_replace[] = '<?php foreach (\\2) { ?>';
        $this->_template_preg[] = '/' . $this->__ltag . 'for\{(.*?)\}' . $this->__rtag . '/i';
        $this->_template_replace[] = '<?php for (\\1) { ?>';

        //注释标签
        $this->_template_preg[] = '/' . $this->__ltag . '\{(\#|\*)(.*?)(\#|\*)\}' . $this->__ltag . '/';
        $this->_template_replace[] = '';

        //引入页面标签
        $this->_template_preg[] = '/<!--#include\s*file=[\"|\'](.*)\.(html|htm)[\"|\']-->/';
        $this->_template_replace[] = "<?php \$__Template->display(\"" . config('TPL.TPL_URL') . config('TPL.TPL_THEME') . "/$1\"); ?>";

        //引入页面引入
        $this->_template_preg[] = '/{include\s*file=\"(.*)\"}/i';
        $this->_template_replace[] = "<?php \$__Template->display(\"$1\"); ?>";

        //替换图片CSS等路径
        $template = preg_replace_callback('/<(.*?)(src=|href=|value=|background=)[\"|\'](images\/|img\/|css\/|js\/|style\/|assets\/)(.*?)[\"|\'](.*?)>/', array($this, 'parseLoad'), $template);

        //替换变量标签(必须最后处理)
        $template = preg_replace_callback('/\$\w+((\.\w+)*)?/', array($this, 'parseVar'), $template);
        $this->_template_preg[] = '/' . $this->__ldel . '((( *(\+\+|--) *)*?(([_a-zA-Z][\w]*\(.*?\))|\$((\w+)((\[|\()(\'|")?\$*\w*(\'|")?(\)|\]))*((->)?\$?(\w*)(\((\'|")?(.*?)(\'|")?\)|))){0,})( *\.?[^ \.]*? *)*?){1,})' . $this->__rdel . '/i';
        $this->_template_replace[] = '<?php echo \\1;?>';

        //结束符号
        $this->_template_preg[] = '/' . $this->__ltag . '\{\/(.*?)\}' . $this->__rtag . '/i';
        $this->_template_replace[] = '<?php } ?>';

        // 替换所有标签
        $template = preg_replace($this->_template_preg, $this->_template_replace, $template);

        //替换通用循环
        $template = preg_replace_callback('/' . $this->__ltag . '(\w+){([^"].*)}' . $this->__rtag . '/i', array($this, 'parseFor'), $template);

        //替换常量
        $template = str_replace('__PUBLIC__', PUBLIC_URL, $template);
        $template = str_replace('__ROOT__', ROOT_URL, $template);
        $template = str_replace('__TPL__', ROOT_URL.config('TPL.TPL_URL').config('TPL.TPL_THEME').'/', $template);
        return $template;
	}

    /**
     * 解析循环标签
     * @param array $var
     * @return string
     */
    private function parseFor($var) {
        $tpl = trim($var[2]);
        $item = trim($var[1]);
        $tpl = ' ' . $tpl;
        $tpl = preg_replace("/\s([_a-zA-Z]+)=/", ', "\1"=>', $tpl);
        $tpl = substr($tpl, 1);
        //匹配必要参数
        $dataArray = array();
        if(preg_match_all('/\s"([_a-zA-Z]+)"=>"(.+?)"/', $tpl, $result)){
            foreach ($result[1] as $key => $value) {
                $dataArray[$value] = $result[2][$key];
            }
        }
        //生成模块调用
        $html = '<?php $'.$item.'List = service("'.strtolower($dataArray['app']).'","Label","'.$dataArray['label'].'",array('.$tpl.')); ';
        switch ($item) {
            case 'echo':
                $html .= ' echo $'.$item.'List; ?>'; 
                break;
            case 'assign':
                $html .= '$'.$dataArray['list'].' = $'.$item.'List; ?>'; 
                break;
            default:
                $html .= ' if(is_array($'.$item.'List)) foreach($'.$item.'List as $'.$item.'){ ?>';
                break;
        }
        return $html;
    }

    /**
     * 解析变量
     * @param array $var
     * @return string
     */
    private function parseVar($var) {
        if (empty($var[0])){
            return;
        }
        $vars = explode('.', $var[0]);
        $var = array_shift($vars);
        $name = $var;
        foreach ($vars as $val){
            $name .= '["' . $val . '"]';
        }
        return $name;
    }

    /**
     * 解析文件路径标签
     * @param array $var
     * @return string
     */
    private function parseLoad($var) {
        $file = $var[3].$var[4];
        $url = config('TPL.TPL_URL') . config('TPL.TPL_THEME');
        if(substr($url, 0,1) == '.'){
            $url = substr($url, 1);
        }
        $url = str_replace('\\', '/', $url);
        $url = ROOT_URL . $url . '/' . $file;
        $html = '<'.$var[1].$var[2].'"'.$url.'"'.$var[5].'>';
        return $html;
    }

}